/**
 * Mona Esmaeili and Gabriele Cerfoglio
 */

package sa4


import javax.servlet.http._
import javax.servlet.ServletConfig
import scala.xml._
import org.squeryl.KeyedEntity
import org.squeryl.SessionFactory
import org.squeryl.Session
import org.squeryl.adapters.H2Adapter
import sa4.routing._
import sa4.template._
import scala.xml.PrettyPrinter
import scala.xml.NodeSeq
import scala.xml.Elem
import org.squeryl.PrimitiveTypeMode._
import org.squeryl.dsl.ast.LogicalBoolean
import org.squeryl.annotations.OptionType


//DataBase


class User(val surname: String, val lastname: String ,val email:String) extends KeyedEntity[Long] {
  val id = 0L
  def this() = this("", "","")
}



class Passenger(val firstName: String, val lastName: String ,val email:String, val destination:String, val departure:String, val code:Int) extends KeyedEntity[Long] {
  val id = 0L
  def this() = this("", "","", "", "", 0)
}

object AirLine extends org.squeryl.Schema {
  val reservations = table[Passenger]
}










class SimpleServletWithForms extends HttpServlet{
   type HandlerFunction = (HttpServletRequest, HttpServletResponse) => Unit
   val routing = new Routing()
   val template=new Template() 
  
  override def init(config: ServletConfig) {
	  super.init(config)
	  
	  //Starting the database
	  Class.forName("org.h2.Driver")

	  SessionFactory.concreteFactory = Some(() =>
	  Session.create(
			  java.sql.DriverManager.getConnection("jdbc:h2:" + System.getProperty("user.dir") + "/test"),
			  new H2Adapter))
			  
			  
	 transaction {      
      AirLine.drop
      AirLine.create
      AirLine.reservations.insert(new Passenger ("sdfdsf", "sddfsdf", "dsjkhds", "jhj", "blargh", 666))

    }
	
	  // adding routing  
	  routing.addRoute("/", loadHome)
	  routing.addRoute("/Shop.css", css)
	  routing.addRoute("/airline.jpg", picture)
  }
  override def service(req: HttpServletRequest, resp: HttpServletResponse) {
    //Routing dispatch
    if (routing.tableDispatch(req, resp))
      return
    resp.sendError(HttpServletResponse.SC_NOT_FOUND)

  }
  
 
  def loadHome(req: HttpServletRequest, resp: HttpServletResponse) = {
    val xml = template.loadPage("index.html")
    val html = prepareForm(xml)
    resp.getWriter.write(new PrettyPrinter(72, 2).formatNodes(html))
  }
  def css(req: HttpServletRequest, resp: HttpServletResponse) {
    val css = template.loadCss("Shop.css")
    resp.getWriter.write(css)
    resp.setContentType("text/css")
  }
  
    def picture(req: HttpServletRequest, resp: HttpServletResponse) {
    val pic = template.loadCss("airline.jpg")
    resp.getWriter.write(pic)
    resp.setContentType("image/jpg")
  }
   
    
    def searchPassenger(code: String) = {
      <html>
      <head>
        <title>Results for { code }</title>
      </head>
      <body>
        {
          if (code.forall(_.isDigit) && code.length() != 0) {
          transaction {
            for (s <- from(AirLine.reservations)(s => where(s.code === (code.toInt)) select (s))) yield {
              <div>
                <h3>Information on passenger { s.code }:</h3>
                <ul>
                	<li>First Name: { s.firstName } </li>
                	<li>Last Name: { s.lastName } </li>
                	<li>Email Adress: { s.email } </li>
                	<li>Destination: { s.destination } </li>
                	<li>Departure: { s.departure } </li>
                </ul>
              </div>                     	
            }
          }
          }
          else {
            <h3>Invalid Passenger Code</h3>
          }
        }
        <a href="/">Back</a>
      </body>
    </html>
    }
    
      def listPassengers(code: String) = {
      <html>
      <head>
        <title>All registered passengers: </title>
      </head>
      <body>
        {
          transaction {
            for (s <- from(AirLine.reservations)(s => where(s.code === s.code) select (s))) yield {
              <div>
                <h3>Information on passenger { s.code }:</h3>
                <ul>
                	<li>First Name: { s.firstName } </li>
                	<li>Last Name: { s.lastName } </li>
                	<li>Email Adress: { s.email } </li>
                	<li>Destination: { s.destination } </li>
                	<li>Departure: { s.departure } </li>
                </ul>
              </div>                     	
            }
          }
        }
        <a href="/">Back</a>
      </body>
    </html>
    }
      
      
       
    def registerPassenger(firstName: String, lastName: String, email: String, destination: String, departure: String, code: String) = {
      
      
   
    val filled = firstName.length() != 0 && lastName.length() != 0 && email.length() != 0 && destination.length() != 0 && departure.length() != 0
    
    if (code.forall(_.isDigit) && code.length() != 0 && filled) {
      
      transaction {
      AirLine.reservations.insert(new Passenger(firstName, lastName, email, destination, departure, code.toInt))
    }
      
   <html>
      <head>
        <title>User detail</title>
        <link rel="stylesheet" href="reserve.css"/>
      </head>
      <body>
        <h3> Passenger { code }, { firstName } { lastName } has been added </h3>
        <a href="/">Back</a>
        
      </body>
    </html>  
    }
    else {
      <html>
      <head>
        <title>User detail</title>
        <link rel="stylesheet" href="reserve.css"/>
      </head>
      <body>
        <h3> Invalid Passenger Details </h3>
        <a href="/">Back</a>
        
      </body>
    </html>  
    }
    
    
  
    }   
       
    
    
 def removePassenger(code: String) = {
      
     
    transaction {
      AirLine.reservations.deleteWhere(s => s.code === code.toInt)
    }

    <html>
      <head>
        <title>User detail</title>
        <link rel="stylesheet" href="reserve.css"/>
      </head>
      <body>
        <h3> Passenger { code } has been removed </h3>
        <a href="/">Back</a>
        
      </body>
    </html>
  }
  

 

  
  
  //FORM

  /**
   * Prepare the form
   * @param template The template of the form we are using
   * @return NodeSeq The template changed
   */
  def prepareForm(template: NodeSeq): NodeSeq = {
    import scala.xml.transform._
    import scala.xml.Null // hide scala.Null
    object MakeForm extends RewriteRule {
      override def transform(n: Node): Seq[Node] = n match {
        case form: Elem if form.label == "form" =>
          val Some(handler) = form.attribute("handler")
          var Some(method) = form.attribute("method")

          // Make the handler and install in routeTable
          val (uri, f: HandlerFunction) = makeHandler(handler.text)

          routing.addRoute(uri, f)

          // Add an action to the form.
          form % Attribute(None, "action", Text(uri), Null)
        case n => n
      }
    }
    template.map(ns => new RuleTransformer(MakeForm)(ns))
  }

  /**
   * Creates a new path with its corresponding function
   * @param s
   * @return String A new path
   * @return HandlerFunction The corresponding function
   */
  def makeHandler(s: String): (String, HandlerFunction) = {
    // Parse the handler string.
    val q = "^(\\w+)\\((.*)\\)$".r

    val (methodName, argNames) = s match {
      case q(methodName, argNames) => (methodName, argNames.split(",").map(_.trim))
      case _ => throw new RuntimeException("bad handler: " + s)
    }

    // Look for a method that takes the right number of strings.
    val method = this.getClass.getMethod(methodName, argNames.map(_ => classOf[String]): _*)
    val h = (req: HttpServletRequest, resp: HttpServletResponse) => {
      val result = method.invoke(this, argNames.map(k => req.getParameter(k)): _*)
      result match {
        case s: String =>
          resp.getWriter.write(s)
        case html: NodeSeq =>
          resp.getWriter.write(new PrettyPrinter(72, 2).formatNodes(html))
      }
    }
    (handlerURI(methodName), h)
  }

  /**
   * Constructs a new path with the method name
   * @param methodName The method that will be used as path
   */
  def handlerURI(methodName: String) = {
    "/" + methodName
  }
  
}